package cn.net.yugu.doraemon.netty.handler;

import cn.net.yugu.doraemon.netty.factory.biz.Biz;
import cn.net.yugu.doraemon.netty.factory.biz.BizFactory;
import cn.net.yugu.doraemon.netty.msg.Message;
import cn.net.yugu.doraemon.netty.processor.MessageProcessor;
import cn.net.yugu.doraemon.netty.processor.MessageProcessorNotice;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.ReadTimeoutException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

/**
 * @description:
 * @author: wanghongli
 * @create: 2022-07-12 14:15:59
 */
@Slf4j
public class NettyHandler extends SimpleChannelInboundHandler<Message> {
    protected MessageProcessorNotice processorNotice;
    protected BizFactory bizFactory;
    protected ExecutorService executorService;
    protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();

    public NettyHandler(MessageProcessorNotice processorNotice, BizFactory bizFactory, ExecutorService executorService) {
        this.processorNotice = processorNotice;
        this.bizFactory = bizFactory;
        this.executorService = executorService;
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Message message) throws Exception {
        if(log.isDebugEnabled()) {
            log.debug("from:{}, recv:{}, ", ctx.channel().remoteAddress(), message);
        }

        Biz biz = bizFactory.create(message.getMsgCode());
        if(biz != null) {
            MessageProcessor processor = new MessageProcessor();
            processor.channelHandlerContext = ctx;
            processor.message = message;
            processor.biz = biz;
            processor.attributes = attributes;
            processor.processorNotice = processorNotice;

            executorService.submit(processor);
        }

        log.debug("executorService {}", executorService);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        if(cause instanceof ReadTimeoutException) {
            if(log.isInfoEnabled()) {
                log.info("session timout, {}", ctx.channel().remoteAddress());
            }
        }

        if (cause instanceof NoSuchBeanDefinitionException) {
            log.error(cause.getMessage());
        } else {
            log.error("error", cause);
        }

        ctx.close();
        if(log.isDebugEnabled()) {
            log.error("invoke close()");
        }
    }
}
